package com.hex.ds.hdrs.period.task.service;

import cn.hutool.core.util.StrUtil;
import com.hex.bigdata.hbda.base.Page;
import com.hex.bigdata.hbda.utils.StringUtils;
import com.hex.ds.hdrs.app.po.AppGroupRelationPo;
import com.hex.ds.hdrs.app.service.AppManager;
import com.hex.ds.hdrs.app.service.AppSession;
import com.hex.ds.hdrs.app.service.IAppGroupRelationService;
import com.hex.ds.hdrs.common.annotation.AppCodeVerification;
import com.hex.ds.hdrs.common.constant.Const;
import com.hex.ds.hdrs.common.page.PageData;
import com.hex.ds.hdrs.period.task.converter.IMutexPoolConverter;
import com.hex.ds.hdrs.period.task.dao.MutexPoolDao;
import com.hex.ds.hdrs.period.task.dto.MutexPoolDto;
import com.hex.ds.hdrs.period.task.po.MutexPool;
import com.hex.ds.hdrs.period.task.po.MutexPoolGroup;
import com.hex.ds.hdrs.period.task.po.PeriodTaskDef;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Package: com.hex.ds.hdrs.period.task.service
 * @ClassName MutexPoolService
 * @Description: 互斥池管理
 * @Author: wz.li
 * @Date 2023/7/5 14:52
 * @Version v2.0.2
 **/
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor_ = {@Lazy, @Autowired})
public class MutexPoolService {

    private final MutexPoolDao mutexPoolDao;

    private final IAppGroupRelationService appGroupRelationService;

    private final IMutexPoolConverter mutexPoolConverter;

    private final MutexPoolGroupService mutexPoolGroupService;

    @Autowired
    private AppManager appManager;

    /*
     * @Method: queryAll <br>
     * @Param: [] <br>
     * @Return: java.util.List<com.hex.ds.hdrs.period.task.po.MutexPool> <br>
     * @Description：查询所有互斥池<br>
     * @Author： wz.li<br>
     * @Date： 2023/7/5 14:47 <br>
     * @Version： V2.0.2<br>
     */
    public List<MutexPool> queryAll() {
        return mutexPoolDao.queryList(new MutexPool());
    }

    /*
     * @Method: queryListByPage <br>
     * @Param: [mutexPool, page] <br>
     * @Return: com.hex.ds.hdrs.common.page.PageData <br>
     * @Description：分页查询<br>
     * @Author： wz.li<br>
     * @Date： 2023/7/5 14:46 <br>
     * @Version： V2.0.2<br>
     */
    public PageData queryListByPage(MutexPool mutexPool, Page page) {
        List<MutexPool> mutexPoolList = mutexPoolDao.queryListByPage(mutexPool, page);
        return new PageData(mutexPoolList, page);
    }

    /*
     * @Method: addAppMutexPool <br>
     * @Param: [mutexPoolDto] <br>
     * @Return: void <br>
     * @Description：应用管理员新增互斥任务<br>
     * @Author： wz.li<br>
     * @Date： 2023/7/5 9:51 <br>
     * @Version： V2.0.2<br>
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    @AppCodeVerification(paramObject = MutexPoolDto.class)
    public void addAppMutexPool(MutexPoolDto mutexPoolDto) {
        MutexPool mutexPool = qryMutexPool(mutexPoolDto.getAppCode(), Const.MUTEX_POOL_TYPE_APP);
        if (mutexPool == null) {
            addNewAppMutexPool(mutexPoolDto);
        } else {
            updateMutexPool(mutexPool, mutexPoolDto.getTaskCodes());
        }
        updateMutexTaskForAppSeesion(mutexPoolDto.getAppCode());
    }

    /*
     * @Method: addAdminMutexPool <br>
     * @Param: [mutexPoolDto] <br>
     * @Return: void <br>
     * @Description：系统管理员新增互斥任务<br>
     * @Author： wz.li<br>
     * @Date： 2023/7/5 11:50 <br>
     * @Version： V2.0.2<br>
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void addAdminMutexPool(MutexPoolDto mutexPoolDto) {
        Map<String, List<String>> mutexTaskMap = getTaskDefMap(mutexPoolDto);
        if (mutexTaskMap != null) {
            addNewAdminMutexPool(mutexTaskMap, mutexPoolDto);
            addTaskToAppSessionForAdmin(mutexPoolDto.getGroupCode());
        }
    }

    /*
     * @Method: addNewAdminMutexPool <br>
     * @Param: [mutexTaskMap, mutexPoolDto] <br>
     * @Return: void <br>
     * @Description：系统管理员新增互斥任务-数据库<br>
     * @Author： wz.li<br>
     * @Date： 2023/7/5 13:55 <br>
     * @Version： V2.0.2<br>
     */
    private void addNewAdminMutexPool(Map<String, List<String>> mutexTaskMap, MutexPoolDto mutexPoolDto) {
        for (String appCode : mutexTaskMap.keySet()) {
            MutexPool mutexPool = qryMutexPoolBy(mutexPoolDto.getGroupCode(), appCode);
            if (mutexPool == null) {
                mutexPool = mutexPoolConverter.toMutexPool(appCode, StringUtils.join(mutexTaskMap.get(appCode), ","),
                        mutexPoolDto.getGroupCode(), Const.MUTEX_POOL_TYPE_SYS);
                mutexPoolDao.insert(mutexPool);
            } else {
                updateMutexPool(mutexPool, mutexTaskMap.get(appCode));
            }
        }
    }

    /*
     * @Method: addTaskToAppSessionForAdmin <br>
     * @Param: [groupCode] <br>
     * @Return: void <br>
     * @Description：系统管理员新增互斥任务-内存<br>
     * @Author： wz.li<br>
     * @Date： 2023/7/5 17:30 <br>
     * @Version： V2.0.2<br>
     */
    private void addTaskToAppSessionForAdmin(String groupCode) {
        MutexPoolGroup mutexPoolGroup = mutexPoolGroupService.queryByGroupCode(groupCode);
        List<String> appCodes = Arrays.asList(StrUtil.split(mutexPoolGroup.getAppCodes(), ","));
        for (String appCode : appCodes) {
            updateMutexTaskForAppSeesion(appCode);
        }
    }

    /*
     * @Method: delAdminMutexPool <br>
     * @Param: [mutexPoolDto] <br>
     * @Return: void <br>
     * @Description：系统管理员删除指定互斥任务<br>
     * @Author： wz.li<br>
     * @Date： 2023/7/5 15:05 <br>
     * @Version： V2.0.2<br>
     */
    public void delAdminMutexPool(MutexPoolDto mutexPoolDto) {
        removeAdminMutexPool(mutexPoolDto);
        removeTaskToAppSessionForAdmin(mutexPoolDto.getGroupCode());
    }

    /*
     * @Method: removeAdminMutexPool <br>
     * @Param: [mutexPoolDto] <br>
     * @Return: void <br>
     * @Description：系统管理员删除互斥任务<br>
     * @Author： wz.li<br>
     * @Date： 2023/7/5 15:14 <br>
     * @Version： V2.0.2<br>
     */
    private void removeAdminMutexPool(MutexPoolDto mutexPoolDto) {
        Map<String, List<String>> taskMap = getTaskDefMap(mutexPoolDto);
        if (taskMap != null) {
            for (String appCode : taskMap.keySet()) {
                MutexPool mutexPool = qryMutexPoolBy(mutexPoolDto.getGroupCode(), appCode);
                if (mutexPool != null) {
                    removeMutexPool(mutexPool, taskMap.get(appCode));
                }
            }
        }
    }

    /*
     * @Method: removeTaskToAppSessionForAdmin <br>
     * @Param: [groupCode] <br>
     * @Return: void <br>
     * @Description：系统管理员删除互斥任务-内存<br>
     * @Author： wz.li<br>
     * @Date： 2023/7/5 17:29 <br>
     * @Version： V2.0.2<br>
     */
    private void removeTaskToAppSessionForAdmin(String groupCode) {
        MutexPoolGroup mutexPoolGroup = mutexPoolGroupService.queryByGroupCode(groupCode);
        List<String> appCodes = Arrays.asList(StrUtil.split(mutexPoolGroup.getAppCodes(), ","));
        for (String appCode : appCodes) {
            updateMutexTaskForAppSeesion(appCode);
        }
    }

    /*
     * @Method: getTaskDefMap <br>
     * @Param: [mutexPoolDto] <br>
     * @Return: java.util.Map<java.lang.String,java.util.List<java.lang.String>> <br>
     * @Description：按应用编码整理对应的任务<br>
     * @Author： wz.li<br>
     * @Date： 2023/7/5 13:58 <br>
     * @Version： V2.0.2<br>
     */
    private Map<String, List<String>> getTaskDefMap(MutexPoolDto mutexPoolDto) {
        if (CollectionUtils.isNotEmpty(mutexPoolDto.getTaskList())) {
            Map<String, List<String>> map = new HashMap<>();
            for (PeriodTaskDef periodTaskDef : mutexPoolDto.getTaskList()) {
                List<String> taskList = new ArrayList<>();
                if (map.containsKey(periodTaskDef.getAppCode())) {
                    taskList = map.get(periodTaskDef.getAppCode());
                }
                taskList.add(periodTaskDef.getTaskCode());
                map.put(periodTaskDef.getAppCode(), taskList);
            }
            return map;
        }
        return null;
    }

    /*
     * @Method: appDelMutexPool <br>
     * @Param: [mutexPoolDto] <br>
     * @Return: void <br>
     * @Description：应用管理员删除互斥任务<br>
     * @Author： wz.li<br>
     * @Date： 2023/7/5 14:53 <br>
     * @Version： V2.0.2<br>
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void appDelMutexPool(MutexPoolDto mutexPoolDto) {
        MutexPool mutexPool = qryMutexPool(mutexPoolDto.getAppCode(), Const.MUTEX_POOL_TYPE_APP);
        removeMutexPool(mutexPool, mutexPoolDto.getTaskCodes());
        updateMutexTaskForAppSeesion(mutexPoolDto.getAppCode());
    }

    /*
     * @Method: addNewAppMutexPool <br>
     * @Param: [mutexPoolDto] <br>
     * @Return: void <br>
     * @Description：新增互斥池<br>
     * @Author： wz.li<br>
     * @Date： 2023/7/5 14:57 <br>
     * @Version： V2.0.2<br>
     */
    public void addNewAppMutexPool(MutexPoolDto mutexPoolDto) {
        AppGroupRelationPo relation = appGroupRelationService.queryOneByAppCode(mutexPoolDto.getAppCode());
        String groupCode = "";
        if (relation != null && StringUtils.isNotBlank(relation.getGroupCode())) {
            groupCode = relation.getGroupCode();
        }
        String taskCodes = StringUtils.join(mutexPoolDto.getTaskCodes(), ",");
        MutexPool mutexPool = mutexPoolConverter.toMutexPool(mutexPoolDto.getAppCode(), taskCodes, groupCode, Const.MUTEX_POOL_TYPE_APP);
        mutexPoolDao.insert(mutexPool);

    }

    /*
     * @Method: updateMutexTaskForAppSeesion <br>
     * @Param: [appCode] <br>
     * @Return: void <br>
     * @Description：更新指定应用的内中互斥任务<br>
     * @Author： wz.li<br>
     * @Date： 2023/7/5 17:51 <br>
     * @Version： V2.0.2<br>
     */
    public void updateMutexTaskForAppSeesion(String appCode) {
        List<String> taskCodeList = new ArrayList<>();
        List<MutexPool> mutexPoolList = queryListByAppCode(appCode);
        for (MutexPool mutexPool : mutexPoolList) {
            List<MutexPool> mutexPools = qryMutexPoolList(mutexPool.getGroupCode());
            for (MutexPool mutex : mutexPools) {
                taskCodeList.addAll(Arrays.asList(StrUtil.split(mutex.getTaskCodes(), ",")));
            }
        }
        AppSession appSession = appManager.getValidAppSession(appCode);
        if (appSession != null) {
            appSession.setMutexTask(taskCodeList.stream().distinct().collect(Collectors.toList()));
        }
    }

    /*
     * @Method: updateMutexPool <br>
     * @Param: [mutexPool, taskCodeList] <br>
     * @Return: void <br>
     * @Description：新增互斥池中指定互斥任务<br>
     * @Author： wz.li<br>
     * @Date： 2023/7/5 14:53 <br>
     * @Version： V2.0.2<br>
     */
    public void updateMutexPool(MutexPool mutexPool, List<String> taskCodeList) {
        if (StringUtils.isNotBlank(mutexPool.getTaskCodes())) {
            String[] taskCodes = mutexPool.getTaskCodes().split(",");
            List<String> dbTaskCodeList = Arrays.asList(taskCodes);
            taskCodeList.addAll(dbTaskCodeList);
        }
        taskCodeList = taskCodeList.stream().distinct().collect(Collectors.toList());
        mutexPoolDao.update(mutexPoolConverter.toMutexPool(mutexPool, StrUtil.join(",", taskCodeList)));
    }

    /*
     * @Method: removeMutexPool <br>
     * @Param: [mutexPool, taskCodeList] <br>
     * @Return: void <br>
     * @Description：删除互斥池中指定互斥任务<br>
     * @Author： wz.li<br>
     * @Date： 2023/7/5 15:02 <br>
     * @Version： V2.0.2<br>
     */
    public void removeMutexPool(MutexPool mutexPool, List<String> taskCodeList) {
        List<String> newTaskCodes = new ArrayList<>();
        if (StringUtils.isNotBlank(mutexPool.getTaskCodes())) {
            Collections.addAll(newTaskCodes, StrUtil.split(mutexPool.getTaskCodes(), ","));
            newTaskCodes.removeAll(taskCodeList);
        }
        if (CollectionUtils.isNotEmpty(newTaskCodes)) {
            mutexPoolDao.update(mutexPoolConverter.toMutexPool(mutexPool, StrUtil.join(",", newTaskCodes)));
        } else {
            mutexPoolDao.delMutexPool(mutexPool.getPkId());
        }

    }

    /*
     * @Method: qryMutexPoolList <br>
     * @Param: [groupCode] <br>
     * @Return: java.util.List<com.hex.ds.hdrs.period.task.po.MutexPool> <br>
     * @Description：根据互斥组编码查询<br>
     * @Author： wz.li<br>
     * @Date： 2023/7/5 14:30 <br>
     * @Version： V2.0.2<br>
     */
    public List<MutexPool> qryMutexPoolList(String groupCode) {
        return mutexPoolDao.queryList(new MutexPool().setGroupCode(groupCode));
    }

    /*
     * @Method: qryMutexPool <br>
     * @Param: [appCode, poolType] <br>
     * @Return: com.hex.ds.hdrs.period.task.po.MutexPool <br>
     * @Description：根据应用编码查询对应的应用互斥池<br>
     * @Author： wz.li<br>
     * @Date： 2023/7/5 17:04 <br>
     * @Version： V2.0.2<br>
     */
    public MutexPool qryMutexPool(String appCode, String poolType) {
        MutexPool mutexPool = new MutexPool().setAppCode(appCode).setPoolType(poolType);
        return mutexPoolDao.queryOne(mutexPool);
    }

    public List<MutexPool> queryListByAppCode(String appCode) {
        MutexPool mutexPool = new MutexPool().setAppCode(appCode);
        return mutexPoolDao.queryList(mutexPool);
    }

    /*
     * @Method: qryMutexPoolBy <br>
     * @Param: [groupCode, appCode] <br>
     * @Return: com.hex.ds.hdrs.period.task.po.MutexPool <br>
     * @Description：根据互斥组编码和应用编码查询对应的互斥池<br>
     * @Author： wz.li<br>
     * @Date： 2023/7/5 14:34 <br>
     * @Version： V2.0.2<br>
     */
    public MutexPool qryMutexPoolBy(String groupCode, String appCode) {
        MutexPool mutexPool = new MutexPool().setAppCode(appCode).setGroupCode(groupCode);
        return mutexPoolDao.queryOne(mutexPool);
    }

    /*
     * @Method: removeByGroupCode <br>
     * @Param: [groupCode] <br>
     * @Return: void <br>
     * @Description：根据互斥组编码删除<br>
     * @Author： wz.li<br>
     * @Date： 2023/7/5 17:51 <br>
     * @Version： V2.0.2<br>
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void removeByGroupCode(String groupCode) {
        List<MutexPool> mutexPoolList = qryMutexPoolList(groupCode);
        mutexPoolDao.delByGroupCode(groupCode);
        for (MutexPool mutexPool : mutexPoolList) {
            updateMutexTaskForAppSeesion(mutexPool.getAppCode());
        }
    }
}
